#include "include/simple_encoder.h"
#include "qbprotocol/proto/table/StopCodec.h"
#include <stdint.h>

#ifndef WIN32
#define _countof(x) (sizeof(x) / sizeof((x)[0]))
#endif

namespace qb{
	namespace base{
		using namespace qb::proto;
		namespace{
#ifdef WIN32
            typedef uint64_t u64;
#else
            typedef unsigned long long u64;
#endif
			class U64Mask{
				u64 mask = 0;
			public:
				U64Mask() :mask(0){}
				U64Mask(u64 m) :mask(m){}
				void set(int i){ mask |= ((u64)1LL << i); }
				bool test(int i)const{
					u64 k = ((u64)1LL << i);
					return mask & k;
				}
				operator u64()const{ return mask; }
			};

			template<int N>
			class StackAllocator : public VarAllocator{
				int				m_used;
				OnceAllocator	m_page;
				char			m_stack[N];
			public:
				StackAllocator() :m_used(0){}
				virtual void Reset(){ m_page.Reset(); m_used = 0; }
				virtual char* AllocString(const char* str, int len)
				{
					if (m_used + len + 1 < N)
					{
						memcpy(m_stack + m_used, str, len);
						m_used += len;
						m_stack[m_used] = '\0';
						return m_stack + m_used;
					}
					return const_cast<char*>(m_page.AddString(str, len));
				}
			};

		}
		MetaObject::MetaObject(const char* name, int size) :m_name(name), m_size(size)
		{

		}

		int MetaObject::AddField(const char* name, kExpectType type, int offset, int size)
		{
			m_fields.emplace_back(FieldInfo{ type, name, offset, size });
			return m_fields.size() - 1;
		}

		/////////////////////////////////////////////////////////////////////////////////
		void EncodeBuf::Free(char* buf)
		{
			if (buf)delete[] buf;
		}
		char* EncodeBuf::Alloc(int size)
		{
			return new char[size];
		}
		SimpleEncoder::SimpleEncoder()
		{

		}

		SimpleEncoder::~SimpleEncoder()
		{

		}

		bool SimpleEncoder::AddMetaObject(int id,MetaObject* meta)
		{
			auto it = m_metamap.find(id);
			if (it != m_metamap.end())
				return false;
			if (id >= 64)
				return false;
			m_metamap.emplace(id, meta);
			return true;
		}
		char*  SimpleEncoder::Encode(const char* data, int size,int id,int& length)
		{
			// 将原生的C++结构体编码到指定内存out中去,根据id找指定的MetaObject对象
			auto it = m_metamap.find(id);
			MetaObject* meta = it->second;
			unsigned char headbuf[128] = { 0 };
			unsigned char tempbuf[1024] = { 0 };
			const auto& fields = meta->GetFields();
			StopCodec codec(tempbuf, _countof(tempbuf), true);
			StopCodec header(headbuf, _countof(headbuf), true);
			// 编码特殊头部
			// 1.id
			// 2.len
			// 3.dft

			// 下面是编码每个字段
			U64Mask mask;
			for (int i = 0; i < (int)fields.size(); i++)
			{
				const FieldInfo& fi = fields[i];

				switch (fi.type)
				{
				case kExpectTypeInt:
					if (fi.size == 1)
					{
						char c = *(char*)(data + fi.offset);
						if (c == 0){ mask.set(i); }
						else codec.AddValue(kEncodeTypeVarInt, VarValue(c));
					}
					else if (fi.size == 2)
					{
						unsigned short s = *(unsigned short*)(data + fi.offset);
						if (s == 0)mask.set(i);
						else codec.AddValue(kEncodeTypeVarInt, VarValue(s));
					}
					else if (fi.size == 4)
					{
						int num = *(int*)(data + fi.offset);
						if (num == 0)mask.set(i);
						else codec.AddValue(kEncodeTypeVarInt, VarValue(num));
					}
					else
					{
#ifdef WIN32
                        unsigned __int64 u = *(unsigned __int64*)(data + fi.offset);
#else
                        unsigned long long u = *(unsigned long long*)(data + fi.offset);
#endif
						if (u == 0)mask.set(i);
						else codec.AddValue(kEncodeTypeVarUint, VarValue(u));
					}
					break;
				case kExpectTypeString:
				{
					int len = strlen(data + fi.offset);
					if (len <= 0)mask.set(i);
					else codec.AddValue(kEncodeTypeStrRaw, VarValue(data + fi.offset, len));
				}break;
				case kExpectTypeDouble:
					break;
				}
			}

			int len = codec.GetPos();
			header.AddValue(kEncodeTypeVarInt, VarValue(id << 3 | BIT_FLAG_DFT));
			header.AddValue(kEncodeTypeVarInt, VarValue(len));
			header.AddValue(kEncodeTypeVarUint, VarValue(mask));

			int headlen = header.GetPos();
			char* out = EncodeBuf::Alloc(headlen + len);
			memcpy(out, headbuf, headlen);
			memcpy(out + headlen, tempbuf, len);
			length = headlen + len;
			return out;
		}
		int SimpleEncoder::Encode(const char* data, int size, int id, char* out, int capcity)
		{
			// 将原生的C++结构体编码到指定内存out中去,根据id找指定的MetaObject对象
			auto it = m_metamap.find(id);
			MetaObject* meta = it->second;
			unsigned char headbuf[128] = { 0 };
			unsigned char tempbuf[1024] = { 0 };
			const auto& fields = meta->GetFields();
			StopCodec codec(tempbuf, _countof(tempbuf), true);
			StopCodec header(headbuf, _countof(headbuf), true);
			// 编码特殊头部
			// 1.id
			// 2.len
			// 3.dft

			// 下面是编码每个字段
			U64Mask mask;
			for (int i = 0; i < (int)fields.size(); i++)
			{
				const FieldInfo& fi = fields[i];

				switch (fi.type)
				{
				case kExpectTypeInt:
					if (fi.size == 1)
					{
						char c = *(char*)(data + fi.offset);
						if (c == 0){ mask.set(i); }
						else codec.AddValue(kEncodeTypeVarInt, VarValue(c));
					}
					else if (fi.size == 2)
					{
						unsigned short s = *(unsigned short*)(data + fi.offset);
						if (s == 0)mask.set(i);
						else codec.AddValue(kEncodeTypeVarInt, VarValue(s));
					}
					else if (fi.size == 4)
					{
						int num = *(int*)(data + fi.offset);
						if (num == 0)mask.set(i);
						else codec.AddValue(kEncodeTypeVarInt, VarValue(num));
					}
					else
					{
#ifdef WIN32
                        unsigned __int64 u = *(unsigned __int64*)(data + fi.offset);
#else
                        unsigned long long u = *(unsigned long long*)(data + fi.offset);
#endif
						if (u == 0)mask.set(i);
						else codec.AddValue(kEncodeTypeVarUint, VarValue(u));
					}
					break;
				case kExpectTypeString:
				{
					int len = strlen(data + fi.offset);
					if (len <= 0)mask.set(i);
					else codec.AddValue(kEncodeTypeStrRaw, VarValue(data + fi.offset, len));
				}break;
				case kExpectTypeDouble:
					break;
				}
			}

			int len = codec.GetPos();
			header.AddValue(kEncodeTypeVarInt, VarValue(id << 3 | BIT_FLAG_DFT));
			header.AddValue(kEncodeTypeVarInt, VarValue(len));
			header.AddValue(kEncodeTypeVarUint, VarValue(mask));

			int headlen = header.GetPos();
			memcpy(out, headbuf, headlen);
			memcpy(out + headlen, tempbuf, len);
			return headlen + len;
		}

		int SimpleEncoder::Decode(const void* data, int size, char* out, int capcity)
		{
			// 将之前编码号的数据,解码到out中去,id是第一个字符的3-7bit
			StopCodec codec((unsigned char*)data, size, false);
			VarValue id, len, dft;
			StackAllocator<1024> alloc;
			codec.GetValue(kEncodeTypeVarInt, id, &alloc);
			codec.GetValue(kEncodeTypeVarInt, len, &alloc);
			codec.GetValue(kEncodeTypeVarUint, dft, &alloc);
			int pos = codec.GetPos();
			MetaObject* meta = GetMetaObject((int)(id.i >> BIT_FLAG_COUNT));
			if (meta == nullptr || meta->GetSize() > capcity)
				return -1;
			if (len.i + pos != size)
				return -1;
			U64Mask mask(dft.u);
			memset(out, 0, capcity);
			const auto& fields = meta->GetFields();
			for (int i = 0; i < (int)fields.size(); i++)
			{
				const FieldInfo& fi = fields[i];
				if (mask.test(i))continue;
				VarValue vv;
				switch (fi.type)
				{
				case kExpectTypeInt:
					codec.GetValue(fi.size == 8 ? kEncodeTypeVarUint : kEncodeTypeVarInt, vv, &alloc);
					if (fi.size == 1)
						out[fi.offset] = (char)vv.i;
					else if (fi.size == 2)
						*((unsigned short*)(out + fi.offset)) = (unsigned short)vv.i;
					else if (fi.size == 4)
						*((unsigned int*)(out + fi.offset)) = (unsigned int)vv.i;
					else
#ifdef WIN32
                        *((unsigned __int64*)(out + fi.offset)) = (unsigned __int64)vv.i;
#else
                        *((unsigned long long*)(out + fi.offset)) = (unsigned long long)vv.i;
#endif
					break;
				case kExpectTypeString:
					codec.GetValue(kEncodeTypeStrRaw, vv, &alloc);
					memcpy(out + fi.offset, vv.str.ptr, vv.str.len);
					break;
				};
			}
			pos = codec.GetPos();
			return pos;
		}

		MetaObject* SimpleEncoder::GetMetaObject(int id)
		{
			auto it = m_metamap.find(id);
			return it != m_metamap.end() ? it->second : nullptr;
		}

	}//namespace base;
}//namespace ss;
